package com.codi.bus.core.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.codi.base.cache.CacheUtil;
import com.codi.base.exception.BaseAppException;
import com.codi.base.util.*;
import com.codi.bus.constant.CacheKeyConst;
import com.codi.bus.constant.GlobalConstant;
import com.codi.bus.core.domain.FundInfo;
import com.codi.bus.core.resultModel.CollectionResult;
import com.codi.bus.core.service.*;
import com.codi.bus.core.service.model.ConfirmModel;
import com.codi.bus.core.service.model.FundSimpleNetValueModel;
import com.codi.fundData.domain.FundNetValueCashe;
import com.codi.fundData.domain.SecurityProduct;
import com.codi.fundData.service.FundMMYieldPerformanceService;
import com.codi.fundData.service.FundNetValueCasheService;
import com.codi.fundData.service.FundNetValuePerformanceService;
import com.codi.fundData.service.FundNetValueService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.*;

@Service("fundNetValueBackService")
@Slf4j
public class FundNetValueBackServiceImpl implements FundNetValueBackService {
    @Autowired
    private FundNetValueService fundNetValueService;

    @Autowired
    private FundInfoService fundInfoService;

    @Autowired
    private FundNetValuePerformanceService fundNetValuePerformanceService;

    @Autowired
    private FundDetailService fundDetailService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private QueryService queryService;

    @Autowired
    private FundNetValueCasheService fundNetValueCasheService;

    @Autowired
    private FundMMYieldPerformanceService fundMMYieldPerformanceService;

    @Autowired
    private TradeOrderService tradeOrderService;

    @Override
    public void updateFundNetValue() throws BaseAppException{
        int totalCount = fundInfoService.queryListCount();
        int pageSize = 100;
        int pageTotalIndex = totalCount / pageSize + 1;

        //分页查询
        for (int i = 1; i <= pageTotalIndex; i++) {
            List<FundInfo> fundInfos = fundInfoService.queryList(i, pageSize);

            handleFundInfos(fundInfos);
        }
    }

    @Override
    public List<FundSimpleNetValueModel> getOneYearNetValueByFundCode(String fundCode) throws BaseAppException {
        if (StringUtil.isNotEmpty(fundCode)) {
            String key = CacheUtil.getKey(CacheKeyConst.MF_FUND_NET_VALUE_PERFORMANCE_UNIT_NV, fundCode.trim());
            ValueOperations<String, String> valueOps = redisTemplate.opsForValue();
            String models = valueOps.get(key);

            if (StringUtil.isNotEmpty(models)) {
                List<FundSimpleNetValueModel> valueModels = JSONObject.parseArray(models, FundSimpleNetValueModel.class);

                return valueModels;
            } else {
                return getOneYearNetValue(fundCode);
            }
        }
        return null;
    }

    @Override
    public List<FundSimpleNetValueModel> getOneMonthNetValueByFundCode(String fundCode) throws BaseAppException {
        List<FundSimpleNetValueModel> oneYear = getOneYearNetValueByFundCode(fundCode);

        if (ListUtil.isEmpty(oneYear)) {
            return null;
        }

        List<FundSimpleNetValueModel> oneMonth = new ArrayList<>();
        Date now = new Date();
        Date date = DateUtils.addMondth(now, -1);

        for (FundSimpleNetValueModel model : oneYear) {
            if (model.getTradingDay().before(date)) {
                break;
            }

            oneMonth.add(model);
        }

        return oneMonth;
    }

    @Override
    public List<FundSimpleNetValueModel> getThreeMonthNetValueByFundCode(String fundCode) throws BaseAppException {
        List<FundSimpleNetValueModel> oneYear = getOneYearNetValueByFundCode(fundCode);

        if (ListUtil.isEmpty(oneYear)) {
            return null;
        }

        List<FundSimpleNetValueModel> oneMonth = new ArrayList<>();
        Date now = new Date();
        Date date = DateUtils.addMondth(now, -3);

        for (FundSimpleNetValueModel model : oneYear) {
            if (model.getTradingDay().before(date)) {
                break;
            }

            oneMonth.add(model);
        }

        return oneMonth;
    }

    @Override
    public List<FundSimpleNetValueModel> getSixMonthNetValueByFundCode(String fundCode) throws BaseAppException {
        List<FundSimpleNetValueModel> oneYear = getOneYearNetValueByFundCode(fundCode);

        if (ListUtil.isEmpty(oneYear)) {
            return null;
        }

        List<FundSimpleNetValueModel> oneMonth = new ArrayList<>();
        Date now = new Date();
        Date date = DateUtils.addMondth(now, -6);

        for (FundSimpleNetValueModel model : oneYear) {
            if (model.getTradingDay().before(date)) {
                break;
            }

            oneMonth.add(model);
        }

        return oneMonth;
    }

    @Override
    public List<Date> getTradeDay(String fundCode, Long userId) {
//        Date now = new Date();
//        Date before = DateUtils.addMondth(now, -12);
//        List<Date> dates;
//
//        CollectionResult<ConfirmModel> collectionResult = queryService.queryTradeConfirms(userId, GlobalConstant.MAX_REQUEST_NUM, 1, 1,
//            "1", fundCode, "", before, now, "");
//
//        if (! collectionResult.getSuccess()) {
//            return null;
//        }
//
//        Collection<ConfirmModel> confirmModels = collectionResult.getObjs();
//
//        if (CollectionUtils.isNotEmpty(confirmModels)) {
//            dates = new ArrayList<>(confirmModels.size());
//
//            for (ConfirmModel model : confirmModels) {
//                String affirm_date = model.getAffirmDate();
//
//                if (StringUtil.isNotEmpty(affirm_date)) {
//                    Date tradingDay = DateUtils.stringToDate(affirm_date);
//                    dates.add(tradingDay);
//                }
//            }
//
//            return dates;
//        }

        return tradeOrderService.getConfirmDates(fundCode, userId);
    }

    @Override
    public Page<Map<String, Object>> queryPages(Pageable pageable, String fundCode) {
        if (StringUtil.isNotEmpty(fundCode)) {
            SecurityProduct securityProduct = fundDetailService.getSecurityProduct(fundCode.trim());

            if (securityProduct != null) {
                return fundNetValueCasheService.queryPage(pageable, securityProduct.getInnerCode());
            }
        }

        return null;
    }

    @Override
    public Page<Map<String, Object>> queryMMPages(Pageable pageable, String fundCode) {
        if (StringUtil.isNotEmpty(fundCode)) {
            SecurityProduct securityProduct = fundDetailService.getSecurityProduct(fundCode.trim());

            if (securityProduct != null) {
                return fundMMYieldPerformanceService.queryPage(pageable, securityProduct.getInnerCode());
            }
        }

        return null;
    }

    private List<FundSimpleNetValueModel> getOneYearNetValue(String fundCode) throws BaseAppException{
        if (StringUtil.isNotEmpty(fundCode)) {
            SecurityProduct securityProduct = fundDetailService.getSecurityProduct(fundCode.trim());

            if (securityProduct == null) {
                return null;
            }

            List<Map<String, Object>> temp; // 返回结果
            List<FundSimpleNetValueModel> models;


            temp = fundNetValuePerformanceService.selectOneYear(securityProduct.getInnerCode());

            FundInfo fundInfo = fundInfoService.getFundInfoByFundCode(fundCode.trim());

            if (fundInfo != null) {
                if ("2".equals(fundInfo.getFundType())) {
                    temp = fundMMYieldPerformanceService.selectOneYearData(securityProduct.getInnerCode());

                    if (ListUtil.isNotEmpty(temp)) {
                        models = new ArrayList<>(temp.size());

                        for (Map<String, Object> map : temp) {
                            FundSimpleNetValueModel model = new FundSimpleNetValueModel();
                            model.setTradingDay(MapUtils.getDate(map, "TradingDay"));
                            model.setUnitNV(MapUtils.getBigDecimal(map, "LatestWeeklyYield").toString());
                            models.add(model);
                        }

                        return models;
                    }
                }
            }

            if (ListUtil.isNotEmpty(temp)) {
                models = new ArrayList<>(temp.size());

                for (Map<String, Object> map : temp) {
                    FundSimpleNetValueModel model = new FundSimpleNetValueModel();
                    model.setTradingDay(MapUtils.getDate(map, "TradingDay"));
                    model.setUnitNV(MapUtils.getBigDecimal(map, "UnitNV").toString());
                    models.add(model);
                }

                return models;
            }
        }

        return null;
    }

    private void handleFundInfos(List<FundInfo> fundInfos) throws BaseAppException{
        if (fundInfos != null) {
            for (FundInfo fundInfo : fundInfos) {
                String fundTypeName = fundInfo.getFundTypeName();



                SecurityProduct securityProduct = fundDetailService.getSecurityProduct(fundInfo.getFundCode());

                if (securityProduct == null) {
                    continue;
                }

                //获得基金内部编码
                Integer innerCode = securityProduct.getInnerCode();
                List<Map<String, Object>> temp; // 返回结果
                List<FundSimpleNetValueModel> models;

                if (StringUtil.isNotEmpty(fundTypeName)) {
                    if ("货币型".equals(fundTypeName)) {
                        temp = fundMMYieldPerformanceService.selectOneYearData(innerCode);

                        if (ListUtil.isNotEmpty(temp)) {
                            models = new ArrayList<>(temp.size());
                            System.out.println(fundInfo.getFundName() + ":" + fundInfo.getFundCode() + ":" + innerCode);
                            for (Map<String, Object> map : temp) {
                                FundSimpleNetValueModel model = new FundSimpleNetValueModel();
                                model.setTradingDay(MapUtils.getDate(map, "TradingDay"));
                                model.setUnitNV(MapUtils.getBigDecimal(map, "LatestWeeklyYield").toString());
                                models.add(model);
                            }

                            String tempStr = JSONObject.toJSONString(models);
                            String fundCode = fundInfo.getFundCode();
                            String key = CacheUtil.getKey(CacheKeyConst.MF_FUND_NET_VALUE_PERFORMANCE_UNIT_NV, fundCode.trim());

                            redisTemplate.delete(key);

                            ValueOperations<String, String> valueOps = redisTemplate.opsForValue();
                            valueOps.set(key, tempStr);
                        }

                        continue;
                    }
                }

                temp = fundNetValuePerformanceService.selectOneYear(innerCode);
                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");


                if (ListUtil.isNotEmpty(temp)) {
                    models = new ArrayList<>(temp.size());

                    for (Map<String, Object> map : temp) {
                        FundSimpleNetValueModel model = new FundSimpleNetValueModel();
                        model.setTradingDay(MapUtils.getDate(map, "TradingDay"));
                        model.setUnitNV(MapUtils.getBigDecimal(map, "UnitNV").toString());
                        models.add(model);
                    }

                    String modelStr = JSONObject.toJSONString(models);

                    //根据fundCode->一年净值 数据存储至redis
                    String fundCode = fundInfo.getFundCode();
                    String key = CacheUtil.getKey(CacheKeyConst.MF_FUND_NET_VALUE_PERFORMANCE_UNIT_NV, fundCode);

                    redisTemplate.delete(key);

                    ValueOperations<String, String> valueOps = redisTemplate.opsForValue();
                    valueOps.set(key, modelStr);
                }
            }
        }
    }
}
